/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hirt;

import java.nio.ByteBuffer;
import java.util.Vector;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author zamille
 */

public class Player extends Item
{
    //Vector<Automobile> carList;
    String name;
    Vector<Role> roleList;
    //int currentRole;        // index of the active role in the players roleList
    int currentCar;         // index of the car that this player is using.
    Item radio;

    public final static int STATUS_OUT_OF_SESSION   = -1;
    public final static int STATUS_SPECTATOR   = 0;
    public final static int STATUS_ACTIVE      = 1;
    //public final static int STATUS_INSTRUCTOR  = 2;

    public final static String TYPE_STUDENT        = "student";
    public final static String TYPE_INSTRUCTOR     = "instructor";

    final static int NUMBER_OF_STATUSES = 2;

    public Player()
    {
        super();
        defaultValues();
        //name = randomName();

    }

    public Player(String newName)
    {
        super( "player", (Item)null );
        defaultValues();
        setName(newName);           //TODO Test this fully
        owner = null;
    }

    /**
     * Builds an Item from a byte stream, presumably created by an item across the network
     * this item should be identical to that one
     * @param bytes
     * @param items: Master Item List used to build the Item
     */
    public Player(ByteBuffer bytes, Vector<Item> items)
    {
        fromBytes(bytes,items);
    }

    /**
     * Builds an Player from a save string, presumably created by an item when saving to a file
     * this player should be identical to that one
     * @param saveString
     * @param items: Master Item List used to build the Item
     */
    public Player(String text, Vector<Item> items)
    {
        fromSaveString(text,items);
    }


    private void defaultValues()
    {
        name = "hirtPlayer";
        state = STATUS_OUT_OF_SESSION;
        //currentRole = Role.NONE;
        setType( TYPE_STUDENT );

        roleList = new Vector<Role>();
        //List = new Vector<Automobile>();
    }

    public void setName(String newName)
    {
        //if (newName == unique)            // Andrew2Zack:   Perhaps we should try to have server monitor/prevent this.
        name = newName;
    }

    public String getName()
    {
        return name;
    }

    public void addRole(Integer newRole) throws Exception
    {
      if (getStatus() > STATUS_OUT_OF_SESSION )
      {
          if (Role.validId(newRole))
          {
              if (containsRole(newRole) == false )
              {
                  roleList.add(new Role(newRole));
                  state = 0;
              }
              
          }
          else
            throw new Exception("Invalid Role Number");
      }
      else
          throw new Exception("Can't add role when not in session");
    }

    public Role removeRole(Integer newRole) throws Exception
    {
        int index;

        if( containsRole( newRole ) == true )
        {
            index = getRoleIndex(newRole);
        }
        else
        {
            return( null );
        }

        //int index = containsRole(newRole);
        if (index >= 0)
        {
            Role tmp = new Role(newRole);
            Automobile car;
            /*for (int i = 0; i < itemList.size(); i++)
            {
                if (itemList.get(i) instanceof Automobile)
                {
                    car = (Automobile)itemList.get(i);
                    if (car.roleId == newRole)
                    {
                        if (itemList.get(currentCar)==car)
                        {
                            if (itemList.size()>0)
                            {
                                setCurrentCar(0);
                            }
                            else
                            {
                                setCurrentCar(-1);
                            }
                        }
                        itemList.remove(car);
                        i--;
                        car.setOwner(null);
                        if (i <= currentCar)
                        {
                            setCurrentCar(currentCar-1);
                        }

                    }
                }

            }*/
            roleList.remove(index);
            return tmp;
        }
        throw new Exception("Not in list");
    }

    public boolean containsRole(int role)
    {
        for (int i = 0; i < roleList.size(); i++)
        {
            if (role == roleList.elementAt(i).getId())
            {
                return( true );
            }
        }

        return( false );
    }

    public int getRoleIndex(int newRole)
    {
        for (int i = 0; i < roleList.size(); i++)
        {
            if (roleList.get(i).getId() == newRole)
                return i;
        }
        return -1;
    }

    public Vector<Role> getRoles()
    {
        return roleList;
    }

    //TODO add throw exception
    @Override
    public void setStatus(int newStatus)
    {
        if (newStatus >= STATUS_OUT_OF_SESSION && newStatus <= NUMBER_OF_STATUSES)
        {
            super.setStatus(newStatus);
        }
    }

    @Override
    public int getStatus()
    {
        return state;
    }

    public boolean addCar(Automobile newCar)
    {
        if (getStatus() > STATUS_OUT_OF_SESSION )
        {
            newCar.setOwner(this);
            itemList.add(newCar);
            setCurrentCar(newCar);
            return true;
        }
        return false;
    }

    public Vector<Automobile> getCarList()
    {
        int index;

        Vector<Automobile> carList = new Vector<Automobile>();

        for( index = 0; index < itemList.size(); index++ )
        {
            Item tempItem = itemList.get( index );

            if( tempItem instanceof Automobile )
            {
                carList.add( ( Automobile )tempItem );
            }
        }

        return( carList );
    }

    public boolean removeCar(Item oldCar)
    {
        int index = itemList.indexOf(oldCar);
        if (index >= 0)
        {
            if (index == currentCar)
            {
                if (itemList.size()<=1)
                    setCurrentCar(-1);
                else
                    setCurrentCar(0);
            }
            else if (index < currentCar)
                setCurrentCar(currentCar-1);
            oldCar.setOwner(null);
            return itemList.remove(oldCar);
        }
        return false;


    }

    public Role getCurrentRole()
    {
        //return roleList.elementAt(currentRole);

        Automobile tempCar = getCurrentCar();
        if (tempCar == null)
        {
            return null;
        }
        else
        {
            return( new Role( tempCar.getRoleId() ) );
        }
    }

/*
    public void setCurrentRole(int currentRole) throws Exception
    {
        if (getStatus() > STATUS_OUT_OF_SESSION )
        {
            if( Role.validId(currentRole) )
            {
                if (containsRole(currentRole) >= 0)
                {
                    this.currentRole = roleList.indexOf(new Role(currentRole));
                }
                else
                {
                    throw new Exception("Player " + name + " doesn't contain role " + Role.getRoleName(currentRole));
                }
            }
            else
                throw new Exception("Invalid Role Number");
        }
        else
            throw new Exception("Can't set roles while not in a session");
    }
*/
    public boolean joinSession(Session mySession) throws Exception
    {
        if (getStatus() == STATUS_OUT_OF_SESSION )
        {
            mySession.addPlayer(this);
            state = STATUS_SPECTATOR; //inSession = true; // Default status of spectator.
            if (mySession.getPlayerList().size() == 1)
            {
                mySession.nextState();
            }
            return true;
        }
        throw new Exception("Already in Session.  Cannot join another");
    }

    public boolean joinSession(Session mySession, int myRole) throws Exception
    {
        if (joinSession(mySession))
        {
            addRole(myRole);
            //setCurrentRole(myRole);
            state = STATUS_ACTIVE;
            return true;
        }
        return false;
    }

    public Session createSession(int id) throws Exception
    {
        Session mySession = new Session(id);
        mySession.setCreator(this);
        if (joinSession(mySession))
        {
            return mySession;
        }
        else
        {
            throw new Exception("Could not join own session");
        }

    }

    public Session createSession(int id, int myRole)  throws Exception
    {
        Session mySession = new Session(id);
        mySession.setCreator(this);
        if (joinSession(mySession, myRole))
        {
            return mySession;
        }
        else
        {
            throw new Exception("Could not join own session");
        }
    }

    //TODO create leaveSession
    /*public boolean leaveSession() throws Exception
    {
        if (inSession)
        {
            if ()
        }
        else
        {
            throw new Exception("Not in Session");
        }
    }*/

    /**
     * setCurrentCar selects which car a player should be using.
     * @param index is the offset or index of which car.
     * @return the car or Automobile requested.
     */
    public Automobile setCurrentCar(int index)
    {
        if (index >= 0 && index < itemList.size())
        {
            currentCar = index;

            Automobile currentAutomobile = (Automobile)itemList.get(currentCar);

            return( currentAutomobile );
        }
        return null;
    }

    public Automobile setCurrentCar(Automobile car)
    {
        if (itemList.contains(car))
        {
            return setCurrentCar(itemList.indexOf(car));
        }
        return null;
    }

    // TODO Zack does not update the current car
    public Automobile getCurrentCar()
    {
        Automobile tempAutomobile;

        if( !itemList.isEmpty() && ( currentCar >= 0 ) && (currentCar < itemList.size()))
        {
            tempAutomobile = ( Automobile )itemList.get( currentCar );
            return( tempAutomobile );
        }
        else
        {
            return null;
        }
    }
    
    private Automobile changeCurrentCar(int changeAmount)
    {
        Automobile tempCar;
        if (itemList.size() == 0)
        {
            return null;
        }
        int tmp = (currentCar + changeAmount)%itemList.size();
        if (tmp >=0 && tmp < itemList.size())
        {
            tempCar = setCurrentCar(tmp);
        }
        else if(tmp < 0)
            tempCar = setCurrentCar(itemList.size()+tmp);
        else
            tempCar = getCurrentCar();

        return tempCar;
    }

    public Automobile nextCar()
    {
        return changeCurrentCar(1);
    }

    public Automobile previousCar()
    {
        return changeCurrentCar(-1);
    }

    /**
     * Returns a ByteBuffer representation of this Item
     * Used to send items over the network
     * @return ByteBuffer
     */
    @Override
    public ByteBuffer toByte()
    {
        ByteBuffer buf = super.toByte();
        buf.putInt(name.getBytes().length);
        buf.put(name.getBytes());
        buf.put((byte)roleList.size());
        for (int i = 0; i < roleList.size(); i++)
            buf.put(roleList.get(i).toByte());
        return buf;
    }

    /**
     * Returns a String representation of this Item
     * Used to save this item to a file
     * @return Save String
     */
    @Override
    public String toSaveString()
    {
        String text = super.toSaveString();
        text += name + "\t";
        text += roleList.size() + "\t";
        for (int i = 0; i < roleList.size(); i++)
            text += roleList.get(i).getId() + "\t";
        return text;
    }

    /**
     * Builds an Item from a byte stream, presumably created by an item across the network
     * this item should be identical to that one
     * @param bytes
     * @param items: Master Item List used to build the action
     * @return what's left of the parem bytes after this method is completes
     */
    @Override
    protected ByteBuffer fromBytes(ByteBuffer bytes, Vector<Item> items)
    {
        bytes = super.fromBytes(bytes, items);
        int length = bytes.getInt(0);
        name = ByteChanger.getString(bytes, 4, length);
        roleList = new Vector<Role>();
        length +=4;
        byte roleNum = bytes.get(length);
        byte role;
        length++;
        for (byte i = 0; i < roleNum; i++)
        {
            role = bytes.get(length);
            length++;
            roleList.add(new Role(role));
        }
        Item item;
        Automobile car;
        for (int i = 0; i < items.size(); i++)
        {
            item = items.get(i);
            if (item instanceof Automobile)
            {
                car = (Automobile)item;
                for (int j = 0; j < roleList.size(); j++)
                {
                    if (roleList.get(j).getId() == car.getRoleId())
                    {
                        itemList.add(car);
                        car.owner = this;
                    }
                }
            }

        }
        try {
            bytes = ByteChanger.truncate(bytes, length);
        } catch (Exception ex) {

        }
        return bytes;
    }

    /**
     * Builds an Item from a save string, presumably read from a save
     * this item should be identical to the one saved in the file
     * @param save string
     * @param items: Master Item List used to build the action
     * @return what's left of the parem SaveString after this methods completes
     */
    @Override
    protected String fromSaveString(String text, Vector<Item> items)
    {
        text = super.fromSaveString(text, items);
        String substring = ByteChanger.getNextValue(text);
        name = substring;

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        int length = Integer.parseInt(substring);
        
        roleList = new Vector<Role>();
        Role role;
        int roleID;
        for (int i = 0; i < length; i++)
        {
            text = ByteChanger.incrementString(text);
            substring = ByteChanger.getNextValue(text);
            roleID = Integer.parseInt(substring);
            role = new Role(roleID);
            roleList.add(role);
        }

        text = ByteChanger.incrementString(text);
        return text;
    }



}
